RippleVoice{

	var player, gui, pulser, name, controls, synthType, midiChannel = '', audioFilePath, transpose = 0, mainOutBus=0, behaviors;

	init{
		behaviors = List.new;	
	}

	addBehavior{|behavior|
		behaviors.add(behavior);	
	}

	playSound{|pitchRatio = 1, volume = 1, pitch|
		behaviors.do({|behavior| // give behaviors a chance to respond
			behavior.playSound;
		});
		//this.getCachedControlValue(\instances).do({
			player.launchSynth(pitchRatio: pitchRatio, volume: volume, pitch: pitch);
		//});
		//this.setGuiFeedback;
	}
	
	playSoundSustainable{|pitchRatio = 1, volume = 1, pitch|
		behaviors.do({|behavior| // give behaviors a chance to respond
			behavior.playSound;
		});
		this.getCachedControlValue(\instances).do({
			player.launchSynth(pitchRatio: pitchRatio, volume: volume, pitch: pitch);
		})
	}
	

	
	releaseSound{
		player.releaseSound;		

	}
	
	setTranspose{|transposeArg|
		transpose	 = transposeArg;
	}
	
	getTranspose{
		^transpose;
	}
	
	soundPlayed{|time, sustain = false|
		Ripple.soundPlayed(name, time, sustain);
	}
	
	// won't increment any plugins
	getCachedControlValue{|control|
		^controls.getCachedValue(control);
	}
	
	getControlsAsArgsArray{
		^controls.getAsArgsArray;
	}
	
	getDescriptor{
		^controls.getDescriptor;
	}
	
	isGuiOpen{
		^gui.isOpen;		
	}
	
	displayGui{
		{
			gui.drawWindow(synthType);
			this.setAllValuesForGui;
			Ripple.selectVoice(this);
		}.defer;
	}
	
	displayPluginGui{|name|
		controls.displayPluginGui(name);	
	}
	
	addPlugin{|name, plugin|
		this.refreshGui;
		^controls.addPlugin(name, plugin);
	}
	
	refreshGui{
		this.setAllValuesForGui;
	}
	
	getControlValue{|which|
		^controls.getValue(which);
	}
	
	setControlValue{|nameArg, valArg, subControlArg|
		var setGuiTo;
		
		behaviors.do({|behavior| // give behaviors a chance to respond
			behavior.setControlValue(nameArg, valArg, subControlArg)
		});
		
		if(controls.exists(nameArg) == false){
			^nil // don't bother with gui stuff if the control doesn't exist
		};
		
		controls.setValue(nameArg, valArg, subControlArg);
		
		if(subControlArg.notNil,{
			setGuiTo = valArg;
		},{
			setGuiTo = controls.getOneToZeroValue(nameArg);
		});
		
		this.setControlGuiValue(nameArg, setGuiTo, subControlArg);
		
		pulser.setControlValue(nameArg, valArg);
		
	}
	
	setControlValueMidi{|midicontrolNumber, valArg|
		controls.setValueMidi(midicontrolNumber, valArg);
	}
	
	setControlGuiValue{|nameArg, valArg, subControlArg|
		gui.setControlValue(nameArg, valArg, subControlArg);	
	}
	
	setControlDataValue{|valArg|
		player.setControlValue(valArg);
	}
	
	setControlValPostLaunch{|name, val|
		player.setControlValPostLaunch(name, val);
	}
	
	setAllValuesForGui{
		controls.sendAllValues;
		gui.setControlValue(\name, this.getName);
		gui.setControlValue(\synthType, this.getSynthType);
		gui.setControlValue(\play, pulser.isRunning);
		gui.setControlValue(\poly, not(player.getPoly));
		gui.setControlValue(\midiChan, this.getMidiChannel);
		gui.setControlValue(\transpose, this.getTranspose);
	}
	
	play{
		pulser.start;
		gui.setControlValue(\play, true);
	}
	
	pause{
		pulser.pause;
		gui.setControlValue(\play, false);
	}
	
	isPlaying{
		^pulser.isRunning;
	}
	
	togglePlayPause{
		if(pulser.isRunning,{
			this.pause;
		},{
			this.play;
		});
	}
	
	setPlayer{|playerArg|
		player = playerArg;
	}
	
	setGui{|guiArg|
		gui = guiArg
	}
	
	setPulser{|pulserArg|
		pulser = pulserArg;
	}
	
	getName{
		if(
			name.notNil,
			{^name},
			{^""}
		);
	}
	
	setName{|nameArg|
		name = nameArg;
	}
	
	setControls{|controlsArg|
		controls = controlsArg;
	}
	
	getSynthType{
		^synthType;
	}
	
	setSynthType{|type|
		synthType = type;
	}
	
	serialize{
		var saveObj;
		saveObj = this.copy;
		^this.writeTextArchive("serializeTest");
	}
	
	commenceHitch{
		Ripple.commenceHitch(name);
	}
	
	freeAllHarnessed{
		Ripple.freeAllHarnessed(name);
	}	
	
	setPoly{|val|
		player.setPoly(val);
	}
	
	getPoly{
		^player.getPoly
	}
	
	reset{
		pulser.reset;
		controls.resetPlugins;
		behaviors.do({|behavior| // give behaviors a chance to respond
			behavior.reset;
		});
		
	}
	
	getMidiChannel{
		^midiChannel	
	}
	
	setMidiChannel{|val|
		if((val != nil) && (val != "nil")){
			midiChannel = val.asInteger;
		}
	}
	
	getAudioFilePath{
		if(audioFilePath == nil){
			audioFilePath = "";
		};
		^audioFilePath;
	}
	
	setAudioFilePath{	|pathArg|
		if(pathArg == nil,
			{audioFilePath = ""},
			{audioFilePath = pathArg}
		);
	}
	
	accept{|xb|
		xb.forVoice(this);	
		controls.accept(xb);
	}
	
	remove{
		pulser.pause;
		player.freeBuffer;
		Ripple.removeVoice(name);
		behaviors.do({|behavior| 
			behavior.tearDown;
		});
		
		
		
	}
	
	setMainOutBus{|busArg|
		mainOutBus = busArg;
	}

	getMainOutBus{
		^mainOutBus;
	}
	
	asString{
		^super.asString + name;
	}

	getNodeId{
		^player.getNodeId;
	}
	
	setBuffer{|buffer|
		player.setBuffer(buffer)
	}
}
